package cn.schoolwow.quickflow.util;

import cn.schoolwow.quickflow.QuickFlowExecutor;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.domain.FlowDataFeature;
import cn.schoolwow.quickflow.domain.FlowExecutorConfig;
import cn.schoolwow.quickflow.flow.BusinessFlow;
import cn.schoolwow.quickflow.flow.CompositeBusinessFlow;
import cn.schoolwow.quickflow.service.executor.QuickFlowExecutorInvocationHandler;
import cn.schoolwow.quickflow.service.flowContext.FlowContextInvocationHandler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class QuickFlowUtil {
    public static String getInstanceClassName(Object instance){
        return instance.getClass().getName();
    }

    /**将实例转换为指定类型*/
    public static <T> T convertToClassType(Object value, Class<T> clazz){
        if(null==value){
            return null;
        }
        if(value.getClass().getName().equalsIgnoreCase(clazz.getName())){
            return (T) value;
        }
        if(value instanceof JSONObject){
            JSONObject object = (JSONObject) value;
            return object.toJavaObject(clazz);
        }
        if(value instanceof JSONArray){
            JSONArray array = (JSONArray) value;
            return array.toJavaObject(clazz);
        }
        try {
            T t = clazz.cast(value);
            return t;
        }catch (ClassCastException e){
            try {
                T t = JSON.parseObject(JSON.toJSONString(value), clazz);
                return t;
            }catch (Exception e1){
                e1.printStackTrace();
                throw new UnsupportedOperationException("无法转换类型!预期类型:"+clazz.getName()+",实际类型:"+value.getClass().getName());
            }
        }
    }

    public static FlowContext getFlowContextInvocationHandler(FlowExecutorConfig flowExecutorConfig){
        FlowContextInvocationHandler flowContextInvocationHandler = new FlowContextInvocationHandler(flowExecutorConfig);
        FlowContext flowContext = (FlowContext) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class<?>[]{FlowContext.class}, flowContextInvocationHandler);
        flowExecutorConfig.flowContext = flowContext;
        return flowContext;
    }

    public static QuickFlowExecutor getQuickFlowExecutorInvocationHandler(FlowExecutorConfig flowExecutorConfig){
        QuickFlowExecutorInvocationHandler quickFlowExecutorInvocationHandler = new QuickFlowExecutorInvocationHandler(flowExecutorConfig);
        QuickFlowExecutor quickFlowExecutor = (QuickFlowExecutor) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class<?>[]{QuickFlowExecutor.class}, quickFlowExecutorInvocationHandler);
        flowExecutorConfig.quickFlowExecutor = quickFlowExecutor;
        return quickFlowExecutor;
    }

    /**
     * 获取流程列表名称
     * */
    public static JSONArray getFlowArray(FlowExecutorConfig flowExecutorConfig){
        JSONArray flowArray = new JSONArray();

        if(null!=flowExecutorConfig.tryCatchFinallyHandler){
            JSONObject flow = new JSONObject();
            flow.put("名称", flowExecutorConfig.tryCatchFinallyHandler.name());
            flow.put("类型", "处理器");
            flow.put("处理器类型", "TryCatchFinally");
            flowArray.add(flow);
        }
        if(null!=flowExecutorConfig.singleFlowListener){
            JSONObject flow = new JSONObject();
            flow.put("名称", flowExecutorConfig.singleFlowListener.name());
            flow.put("类型", "处理器");
            flow.put("处理器类型", "SingleFlow");
            flowArray.add(flow);
        }
        for (BusinessFlow businessFlow : flowExecutorConfig.flowList) {
            JSONObject flow = new JSONObject();
            flow.put("名称", businessFlow.name());
            flow.put("类型", "普通流程");
            flowArray.add(flow);
        }
        return flowArray;
    }

    public static QuickFlowExecutor getCompositeQuickFlowExecutor(CompositeBusinessFlow compositeBusinessFlow, FlowExecutorConfig flowExecutorConfig) {
        FlowExecutorConfig compositeFlowExecutorConfig = new FlowExecutorConfig();
        compositeFlowExecutorConfig.name = compositeBusinessFlow.name();
        compositeFlowExecutorConfig.flowContext = getFlowContextInvocationHandler(compositeFlowExecutorConfig);
        compositeFlowExecutorConfig.currentCompositeFlowDataMap = new ConcurrentHashMap<>();
        compositeFlowExecutorConfig.currentCompositeFlowDataMap.putAll(flowExecutorConfig.currentCompositeFlowDataMap);
        compositeFlowExecutorConfig.parentFlowExecutorConfig = flowExecutorConfig;
        if(null!=flowExecutorConfig.parentFlowExecutorConfig){
            compositeFlowExecutorConfig.currentCompositeFlowDataMap.putAll(flowExecutorConfig.parentFlowExecutorConfig.currentCompositeFlowDataMap);
        }

        compositeFlowExecutorConfig.flowExecutorRootConfig = flowExecutorConfig.flowExecutorRootConfig;
        compositeFlowExecutorConfig.compositeBusiness = true;
        QuickFlowExecutor compositeQuickFlowExecutor = getQuickFlowExecutorInvocationHandler(compositeFlowExecutorConfig);
        compositeBusinessFlow.executeCompositeBusiness(compositeQuickFlowExecutor);
        QuickFlowConfigUtil.loadFlowConfigByName(compositeBusinessFlow.name(), flowExecutorConfig);
        return compositeQuickFlowExecutor;
    }

    public static BusinessFlow getBusinessFlow(CompositeBusinessFlow compositeBusinessFlow){
        String compositeFlowName = "[复合流程]"+compositeBusinessFlow.name();
        BusinessFlow businessFlow = new BusinessFlow() {
            @Override
            public void executeBusinessFlow(FlowContext flowContext) throws Exception {
                FlowExecutorConfig flowExecutorConfig = flowContext.getFlowExecutorConfig();
                QuickFlowExecutor compositeQuickFlowExecutor = getCompositeQuickFlowExecutor(compositeBusinessFlow, flowExecutorConfig);
                compositeQuickFlowExecutor.execute();
            }

            @Override
            public String name() {
                return compositeFlowName;
            }
        };
        return businessFlow;
    }

    public static FlowDataFeature[] addFlowDataFeature(FlowDataFeature addFlowDataFeature, FlowDataFeature[] flowDataFeatures){
        List<FlowDataFeature> flowDataFeatureList = new ArrayList<>();
        for(FlowDataFeature flowDataFeature:flowDataFeatures){
            flowDataFeatureList.add(flowDataFeature);
        }
        if(!flowDataFeatureList.contains(addFlowDataFeature)){
            flowDataFeatureList.add(addFlowDataFeature);
        }
        flowDataFeatures = flowDataFeatureList.toArray(new FlowDataFeature[0]);
        return flowDataFeatures;
    }
}
